Passed
Push — master ( 873606...f8e942 )
by Stephan
08:04
created

collapse.js ➔ ... ➔ show   D

Complexity

Conditions 12
Paths 46

Size

Total Lines 73
Code Lines 41

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 12
eloc 41
nc 46
nop 0
dl 0
loc 73
rs 4.8
c 1
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like collapse.js ➔ ... ➔ show often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/*!
2
  * Bootstrap collapse.js v4.3.1 (https://getbootstrap.com/)
3
  * Copyright 2011-2019 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
4
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
5
  */
6
(function (global, factory) {
7
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('jquery'), require('./util.js')) :
8
  typeof define === 'function' && define.amd ? define(['jquery', './util.js'], factory) :
0 ignored issues
show
Bug introduced by
The variable define seems to be never declared. If this is a global, consider adding a /** global: define */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
9
  (global = global || self, global.Collapse = factory(global.jQuery, global.Util));
0 ignored issues
show
Best Practice introduced by
If you intend to check if the variable self is declared in the current environment, consider using typeof self === "undefined" instead. This is safe if the variable is not actually declared.
Loading history...
Comprehensibility introduced by
Usage of the sequence operator is discouraged, since it may lead to obfuscated code.

The sequence or comma operator allows the inclusion of multiple expressions where only is permitted. The result of the sequence is the value of the last expression.

This operator is most often used in for statements.

Used in another places it can make code hard to read, especially when people do not realize it even exists as a seperate operator.

This check looks for usage of the sequence operator in locations where it is not necessary and could be replaced by a series of expressions or statements.

var a,b,c;

a = 1, b = 1,  c= 3;

could just as well be written as:

var a,b,c;

a = 1;
b = 1;
c = 3;

To learn more about the sequence operator, please refer to the MDN.

Loading history...
10
}(this, function ($, Util) { 'use strict';
11
12
  $ = $ && $.hasOwnProperty('default') ? $['default'] : $;
13
  Util = Util && Util.hasOwnProperty('default') ? Util['default'] : Util;
14
15
  function _defineProperties(target, props) {
16
    for (var i = 0; i < props.length; i++) {
17
      var descriptor = props[i];
18
      descriptor.enumerable = descriptor.enumerable || false;
19
      descriptor.configurable = true;
20
      if ("value" in descriptor) descriptor.writable = true;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
21
      Object.defineProperty(target, descriptor.key, descriptor);
22
    }
23
  }
24
25
  function _createClass(Constructor, protoProps, staticProps) {
26
    if (protoProps) _defineProperties(Constructor.prototype, protoProps);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
27
    if (staticProps) _defineProperties(Constructor, staticProps);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
28
    return Constructor;
29
  }
30
31
  function _defineProperty(obj, key, value) {
32
    if (key in obj) {
33
      Object.defineProperty(obj, key, {
34
        value: value,
35
        enumerable: true,
36
        configurable: true,
37
        writable: true
38
      });
39
    } else {
40
      obj[key] = value;
41
    }
42
43
    return obj;
44
  }
45
46 View Code Duplication
  function _objectSpread(target) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
47
    for (var i = 1; i < arguments.length; i++) {
48
      var source = arguments[i] != null ? arguments[i] : {};
0 ignored issues
show
Best Practice introduced by
Comparing arguments.i to null using the != operator is not safe. Consider using !== instead.
Loading history...
49
      var ownKeys = Object.keys(source);
50
51
      if (typeof Object.getOwnPropertySymbols === 'function') {
52
        ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) {
53
          return Object.getOwnPropertyDescriptor(source, sym).enumerable;
0 ignored issues
show
Bug introduced by
The variable source is changed as part of the for loop for example by arguments.i != null ? arguments.i: {} on line 48. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
54
        }));
55
      }
56
57
      ownKeys.forEach(function (key) {
58
        _defineProperty(target, key, source[key]);
0 ignored issues
show
Bug introduced by
The variable source is changed as part of the for loop for example by arguments.i != null ? arguments.i: {} on line 48. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
59
      });
60
    }
61
62
    return target;
63
  }
64
65
  /**
66
   * ------------------------------------------------------------------------
67
   * Constants
68
   * ------------------------------------------------------------------------
69
   */
70
71
  var NAME = 'collapse';
72
  var VERSION = '4.3.1';
73
  var DATA_KEY = 'bs.collapse';
74
  var EVENT_KEY = "." + DATA_KEY;
75
  var DATA_API_KEY = '.data-api';
76
  var JQUERY_NO_CONFLICT = $.fn[NAME];
77
  var Default = {
78
    toggle: true,
79
    parent: ''
80
  };
81
  var DefaultType = {
82
    toggle: 'boolean',
83
    parent: '(string|element)'
84
  };
85
  var Event = {
86
    SHOW: "show" + EVENT_KEY,
87
    SHOWN: "shown" + EVENT_KEY,
88
    HIDE: "hide" + EVENT_KEY,
89
    HIDDEN: "hidden" + EVENT_KEY,
90
    CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY
91
  };
92
  var ClassName = {
93
    SHOW: 'show',
94
    COLLAPSE: 'collapse',
95
    COLLAPSING: 'collapsing',
96
    COLLAPSED: 'collapsed'
97
  };
98
  var Dimension = {
99
    WIDTH: 'width',
100
    HEIGHT: 'height'
101
  };
102
  var Selector = {
103
    ACTIVES: '.show, .collapsing',
104
    DATA_TOGGLE: '[data-toggle="collapse"]'
105
    /**
106
     * ------------------------------------------------------------------------
107
     * Class Definition
108
     * ------------------------------------------------------------------------
109
     */
110
111
  };
112
113
  var Collapse =
114
  /*#__PURE__*/
115
  function () {
116
    function Collapse(element, config) {
117
      this._isTransitioning = false;
118
      this._element = element;
119
      this._config = this._getConfig(config);
120
      this._triggerArray = [].slice.call(document.querySelectorAll("[data-toggle=\"collapse\"][href=\"#" + element.id + "\"]," + ("[data-toggle=\"collapse\"][data-target=\"#" + element.id + "\"]")));
121
      var toggleList = [].slice.call(document.querySelectorAll(Selector.DATA_TOGGLE));
122
123
      for (var i = 0, len = toggleList.length; i < len; i++) {
124
        var elem = toggleList[i];
125
        var selector = Util.getSelectorFromElement(elem);
126
        var filterElement = [].slice.call(document.querySelectorAll(selector)).filter(function (foundElem) {
127
          return foundElem === element;
128
        });
129
130
        if (selector !== null && filterElement.length > 0) {
131
          this._selector = selector;
132
133
          this._triggerArray.push(elem);
134
        }
135
      }
136
137
      this._parent = this._config.parent ? this._getParent() : null;
138
139
      if (!this._config.parent) {
140
        this._addAriaAndCollapsedClass(this._element, this._triggerArray);
141
      }
142
143
      if (this._config.toggle) {
144
        this.toggle();
145
      }
146
    } // Getters
147
148
149
    var _proto = Collapse.prototype;
150
151
    // Public
152
    _proto.toggle = function toggle() {
153
      if ($(this._element).hasClass(ClassName.SHOW)) {
154
        this.hide();
155
      } else {
156
        this.show();
157
      }
158
    };
159
160
    _proto.show = function show() {
161
      var _this = this;
162
163
      if (this._isTransitioning || $(this._element).hasClass(ClassName.SHOW)) {
164
        return;
165
      }
166
167
      var actives;
168
      var activesData;
169
170
      if (this._parent) {
171
        actives = [].slice.call(this._parent.querySelectorAll(Selector.ACTIVES)).filter(function (elem) {
172
          if (typeof _this._config.parent === 'string') {
173
            return elem.getAttribute('data-parent') === _this._config.parent;
174
          }
175
176
          return elem.classList.contains(ClassName.COLLAPSE);
177
        });
178
179
        if (actives.length === 0) {
180
          actives = null;
181
        }
182
      }
183
184
      if (actives) {
185
        activesData = $(actives).not(this._selector).data(DATA_KEY);
186
187
        if (activesData && activesData._isTransitioning) {
188
          return;
189
        }
190
      }
191
192
      var startEvent = $.Event(Event.SHOW);
193
      $(this._element).trigger(startEvent);
194
195
      if (startEvent.isDefaultPrevented()) {
196
        return;
197
      }
198
199
      if (actives) {
200
        Collapse._jQueryInterface.call($(actives).not(this._selector), 'hide');
201
202
        if (!activesData) {
203
          $(actives).data(DATA_KEY, null);
204
        }
205
      }
206
207
      var dimension = this._getDimension();
208
209
      $(this._element).removeClass(ClassName.COLLAPSE).addClass(ClassName.COLLAPSING);
210
      this._element.style[dimension] = 0;
211
212
      if (this._triggerArray.length) {
213
        $(this._triggerArray).removeClass(ClassName.COLLAPSED).attr('aria-expanded', true);
214
      }
215
216
      this.setTransitioning(true);
217
218
      var complete = function complete() {
219
        $(_this._element).removeClass(ClassName.COLLAPSING).addClass(ClassName.COLLAPSE).addClass(ClassName.SHOW);
220
        _this._element.style[dimension] = '';
221
222
        _this.setTransitioning(false);
223
224
        $(_this._element).trigger(Event.SHOWN);
225
      };
226
227
      var capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1);
228
      var scrollSize = "scroll" + capitalizedDimension;
229
      var transitionDuration = Util.getTransitionDurationFromElement(this._element);
230
      $(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);
231
      this._element.style[dimension] = this._element[scrollSize] + "px";
232
    };
233
234
    _proto.hide = function hide() {
235
      var _this2 = this;
236
237
      if (this._isTransitioning || !$(this._element).hasClass(ClassName.SHOW)) {
238
        return;
239
      }
240
241
      var startEvent = $.Event(Event.HIDE);
242
      $(this._element).trigger(startEvent);
243
244
      if (startEvent.isDefaultPrevented()) {
245
        return;
246
      }
247
248
      var dimension = this._getDimension();
249
250
      this._element.style[dimension] = this._element.getBoundingClientRect()[dimension] + "px";
251
      Util.reflow(this._element);
252
      $(this._element).addClass(ClassName.COLLAPSING).removeClass(ClassName.COLLAPSE).removeClass(ClassName.SHOW);
253
      var triggerArrayLength = this._triggerArray.length;
254
255
      if (triggerArrayLength > 0) {
256
        for (var i = 0; i < triggerArrayLength; i++) {
257
          var trigger = this._triggerArray[i];
258
          var selector = Util.getSelectorFromElement(trigger);
259
260
          if (selector !== null) {
261
            var $elem = $([].slice.call(document.querySelectorAll(selector)));
262
263
            if (!$elem.hasClass(ClassName.SHOW)) {
264
              $(trigger).addClass(ClassName.COLLAPSED).attr('aria-expanded', false);
265
            }
266
          }
267
        }
268
      }
269
270
      this.setTransitioning(true);
271
272
      var complete = function complete() {
273
        _this2.setTransitioning(false);
274
275
        $(_this2._element).removeClass(ClassName.COLLAPSING).addClass(ClassName.COLLAPSE).trigger(Event.HIDDEN);
276
      };
277
278
      this._element.style[dimension] = '';
279
      var transitionDuration = Util.getTransitionDurationFromElement(this._element);
280
      $(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);
281
    };
282
283
    _proto.setTransitioning = function setTransitioning(isTransitioning) {
284
      this._isTransitioning = isTransitioning;
285
    };
286
287
    _proto.dispose = function dispose() {
288
      $.removeData(this._element, DATA_KEY);
289
      this._config = null;
290
      this._parent = null;
291
      this._element = null;
292
      this._triggerArray = null;
293
      this._isTransitioning = null;
294
    } // Private
295
    ;
296
297
    _proto._getConfig = function _getConfig(config) {
298
      config = _objectSpread({}, Default, config);
299
      config.toggle = Boolean(config.toggle); // Coerce string values
300
301
      Util.typeCheckConfig(NAME, config, DefaultType);
302
      return config;
303
    };
304
305
    _proto._getDimension = function _getDimension() {
306
      var hasWidth = $(this._element).hasClass(Dimension.WIDTH);
307
      return hasWidth ? Dimension.WIDTH : Dimension.HEIGHT;
308
    };
309
310
    _proto._getParent = function _getParent() {
311
      var _this3 = this;
312
313
      var parent;
314
315
      if (Util.isElement(this._config.parent)) {
316
        parent = this._config.parent; // It's a jQuery object
317
318
        if (typeof this._config.parent.jquery !== 'undefined') {
319
          parent = this._config.parent[0];
320
        }
321
      } else {
322
        parent = document.querySelector(this._config.parent);
323
      }
324
325
      var selector = "[data-toggle=\"collapse\"][data-parent=\"" + this._config.parent + "\"]";
326
      var children = [].slice.call(parent.querySelectorAll(selector));
327
      $(children).each(function (i, element) {
328
        _this3._addAriaAndCollapsedClass(Collapse._getTargetFromElement(element), [element]);
329
      });
330
      return parent;
331
    };
332
333
    _proto._addAriaAndCollapsedClass = function _addAriaAndCollapsedClass(element, triggerArray) {
334
      var isOpen = $(element).hasClass(ClassName.SHOW);
335
336
      if (triggerArray.length) {
337
        $(triggerArray).toggleClass(ClassName.COLLAPSED, !isOpen).attr('aria-expanded', isOpen);
338
      }
339
    } // Static
340
    ;
341
342
    Collapse._getTargetFromElement = function _getTargetFromElement(element) {
343
      var selector = Util.getSelectorFromElement(element);
344
      return selector ? document.querySelector(selector) : null;
345
    };
346
347
    Collapse._jQueryInterface = function _jQueryInterface(config) {
348
      return this.each(function () {
349
        var $this = $(this);
350
        var data = $this.data(DATA_KEY);
351
352
        var _config = _objectSpread({}, Default, $this.data(), typeof config === 'object' && config ? config : {});
353
354
        if (!data && _config.toggle && /show|hide/.test(config)) {
355
          _config.toggle = false;
356
        }
357
358
        if (!data) {
359
          data = new Collapse(this, _config);
360
          $this.data(DATA_KEY, data);
361
        }
362
363
        if (typeof config === 'string') {
364
          if (typeof data[config] === 'undefined') {
365
            throw new TypeError("No method named \"" + config + "\"");
366
          }
367
368
          data[config]();
369
        }
370
      });
371
    };
372
373
    _createClass(Collapse, null, [{
374
      key: "VERSION",
375
      get: function get() {
376
        return VERSION;
377
      }
378
    }, {
379
      key: "Default",
380
      get: function get() {
381
        return Default;
382
      }
383
    }]);
384
385
    return Collapse;
386
  }();
387
  /**
388
   * ------------------------------------------------------------------------
389
   * Data Api implementation
390
   * ------------------------------------------------------------------------
391
   */
392
393
394
  $(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) {
395
    // preventDefault only for <a> elements (which change the URL) not inside the collapsible element
396
    if (event.currentTarget.tagName === 'A') {
397
      event.preventDefault();
398
    }
399
400
    var $trigger = $(this);
401
    var selector = Util.getSelectorFromElement(this);
402
    var selectors = [].slice.call(document.querySelectorAll(selector));
403
    $(selectors).each(function () {
404
      var $target = $(this);
405
      var data = $target.data(DATA_KEY);
406
      var config = data ? 'toggle' : $trigger.data();
407
408
      Collapse._jQueryInterface.call($target, config);
409
    });
410
  });
411
  /**
412
   * ------------------------------------------------------------------------
413
   * jQuery
414
   * ------------------------------------------------------------------------
415
   */
416
417
  $.fn[NAME] = Collapse._jQueryInterface;
418
  $.fn[NAME].Constructor = Collapse;
419
420
  $.fn[NAME].noConflict = function () {
421
    $.fn[NAME] = JQUERY_NO_CONFLICT;
422
    return Collapse._jQueryInterface;
423
  };
424
425
  return Collapse;
426
427
}));
428
//# sourceMappingURL=collapse.js.map
429